package com.raising.framework.shiro;

import com.raising.framework.entity.ResultCode;
import com.raising.framework.entity.ResultVo;
import com.raising.framework.shiro.entity.CurrentUser;
import com.raising.framework.shiro.realm.MyUsernamePasswordToken;
import com.raising.framework.spring.SpringUtils;
import com.raising.modules.sys.entity.User;
import com.raising.modules.sys.service.UserService;
import com.raising.utils.JStringUtils;
import com.raising.utils.RequestUtils;
import com.raising.utils.UserUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;

/**
 * 自定义表单登录验证
 * @author gaoy
 * 2017 2017-5-7 下午7:24:35
 */
public class MyFormAuthenticationFilter extends FormAuthenticationFilter{

    private static final Logger logger = LoggerFactory.getLogger(MyFormAuthenticationFilter.class);

    private static UserService userService = SpringUtils.getBean(UserService.class);

    public static final String DEFAULT_TYPE_PARAM = "type";
    public static final String DEFAULT_VALIDATECODE_PARAM = "validateCode";
    public static final String DEFAULT_JUMPURL_PARAM = "jumpUrl";

    private String typeParam = DEFAULT_TYPE_PARAM;
    private String validateCodeParam = DEFAULT_VALIDATECODE_PARAM;
    private String jumpUrlParam = DEFAULT_JUMPURL_PARAM;

    protected String getType(ServletRequest request) {
        return WebUtils.getCleanParam(request, getTypeParam());
    }

    protected String getValidateCode(ServletRequest request) {
        return WebUtils.getCleanParam(request, getValidateCodeParam());
    }

    protected String getJumpUrl(ServletRequest request) {
        return WebUtils.getCleanParam(request, getJumpUrlParam());
    }

    /**
     * 登录进入 MyFormAuthenticationFilter 先执行此方法
     * @author GaoYuan
     * @date 2018/11/20 下午3:55
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if(logger.isDebugEnabled()){
            logger.debug("【Shiro】>>> MyFormAuthenticationFilter.isAccessAllowed()，表单登录判断（判断验证码）");
        }
        //从session获取正确验证码
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpSession session = httpServletRequest.getSession();
        //取出session的验证码（正确的验证码）
        String validateCode = (String) session.getAttribute("validateCode");

        // 从cache获取正确的验证码
        String inputCode = getValidateCode(request);

        //判断验证码
        if(inputCode==null||!inputCode.equals(validateCode)){
            //获取跳转的路径
            HttpServletRequest re = (HttpServletRequest)request;
            if (!RequestUtils.isAjax(re)) {
                //如果校验失败，将验证码错误失败信息，通过shiroLoginFailure设置到request中
                request.setAttribute("shiroLoginFailure", "randomCodeError");
            }else{
                HttpServletResponse httpServletResponse = (HttpServletResponse) response;
                /** ajax返回 */
                RequestUtils.ajaxResponse(httpServletResponse,ResultVo.failure(ResultCode.NO_PERMISSIONS).desc("验证码错误"));
            }
            //拒绝访问，不再校验账号和密码
            return false;
        }
        // 如果是登录请求
        if(isLoginRequest(request, response)) {
            // 如果登录允许
            if(isLoginSubmission(request, response)) {
                //本次用户登陆账号
                String account = this.getUsername(request);
                Subject subject = this.getSubject(request, response);
                if(subject != null){
                    //之前登陆的用户
                    CurrentUser currentUser = (CurrentUser)subject.getPrincipal();
                    //如果两次登陆的用户不一样，则先退出之前登陆的用户 - 改为无论如何都删除
                    if (account != null && currentUser != null
//                            && !account.equals(userName)
                            ) {
                        subject.logout();
                    }
                }

            }
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }

    /**
     * 表示登录判断 isAccessAllowed 返回 false 时
     * @author gaoy
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object map) throws Exception {
        if(logger.isDebugEnabled()){
            logger.debug("【Shiro】>>> MyFormAuthenticationFilter.onAccessDenied()，登录验证失败");
        }
        return super.onAccessDenied(request, response, map);
    }

    /**
     * 登录触发
     * 获取登录信息，封装成 AuthenticationToken 对象
     * 本质是自定义的 MyUsernamePasswordToken 对象
     * @author GaoYuan
     * @date 2018/11/20 下午3:45
     */
    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        if(logger.isDebugEnabled()){
            logger.debug("【Shiro】>>> MyFormAuthenticationFilter.createToken()，获取登录信息，封装成 AuthenticationToken 对象");
        }
        String username = getUsername(request);
        String password = getPassword(request);
        String type = getType(request);
        String validateCode = getValidateCode(request);
        String jumpUrl = getJumpUrl(request);
        // 获取是否记住自己
        boolean rememberMe = isRememberMe(request);
        String host = getHost(request);
        return new MyUsernamePasswordToken(username, password.toCharArray(),type,
                validateCode,jumpUrl, rememberMe, host);
    }

    /**
     *  登录成功后会触发此方法
     *  @describe: 自定义跳转路径
     *  @author: GaoYuan
     *  @create_date: 2017/9/30 上午10:27
     *  @param:
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
                                     ServletRequest request, ServletResponse response) throws Exception {
        if(logger.isDebugEnabled()){
            logger.debug("【Shiro】>>> MyFormAuthenticationFilter.onLoginSuccess()，登录成功");
        }
//        issueSuccessRedirect(request, response);
        //获取跳转的路径
        HttpServletRequest re = (HttpServletRequest)request;

        // 更新最后登录时间与ip
        userService.updateLoginInfo(UserUtils.getUserId(),RequestUtils.getRemoteAddr(re),new Date());

        if(RequestUtils.isAjax(re)){
            // 如果是ajax登录
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            RequestUtils.ajaxResponse(httpServletResponse, ResultVo.success());
            return false;
        }else{
            String jumpUrl = re.getParameter("jumpUrl");
            WebUtils.getAndClearSavedRequest(request);
            if (JStringUtils.isNotBlank(jumpUrl)) {
                WebUtils.redirectToSavedRequest(request, response, "/check?jumpUrl=" + jumpUrl);
                return false;
            }
            WebUtils.redirectToSavedRequest(request, response, "/check");
            return false;
        }
    }

    public String getTypeParam() {
        return typeParam;
    }

    public void setTypeParam(String typeParam) {
        this.typeParam = typeParam;
    }

    public String getValidateCodeParam() {
        return validateCodeParam;
    }

    public void setValidateCodeParam(String validateCodeParam) {
        this.validateCodeParam = validateCodeParam;
    }

    public String getJumpUrlParam() {
        return jumpUrlParam;
    }

    public void setJumpUrlParam(String jumpUrlParam) {
        this.jumpUrlParam = jumpUrlParam;
    }

}